#pragma once
#include<thread>
#include<mutex>
#include<vector>
#include<memory>
#include<functional>
#include<sys/eventfd.h>
#include"Channel.hpp"
#include"Poller.hpp"
#include"Log.hpp"
//one thread one eventloop
class EventLoop {
    private:
        using Func_t = std::function<void()>;
        Poller _epoll;//进⾏所有描述符的事件监控
        std::thread::id _thread_id;//线程id（一个EventLoop一个线程）
        int _eventfd;//eventfd唤醒IO时间监控
        std::unique_ptr<Channel> _eventfd_channel;//eventfd对应的channel
        std::vector<Func_t> _tasks;//任务队列
        std::mutex _mutex;//互斥锁,保护任务队列操作的线程安全
    public:
        void RunAllTasks()//执行任务队列中的所有任务
        {
            std::vector<Func_t> tasks;
            {
                std::unique_lock<std::mutex> lock(_mutex);//直接加锁
                tasks.swap(_tasks);//将任务队列中的任务移动到tasks中
            }
            for(auto &task : tasks){
                task();
            }
        }
        void ReadEventfd()//读取eventfd,让其事件清零，避免重复唤醒
        {
            uint64_t value;
            ssize_t n = read(_eventfd, &value, sizeof(value));
            if(n < 0){
                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){
                    LOG_ERR("read eventfd failed %s",strerror(errno));
                    exit(1);
                }
            }
        }
        void WriteEventfd()//写入eventfd,通知IO事件监控
        {
            uint64_t value = 1;
            ssize_t n = write(_eventfd,&value, 1);
            if(n < 0){
                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR){
                    LOG_ERR("write eventfd failed %s",strerror(errno));
                    exit(1);
                }
            }
        }
    public:
        EventLoop()
            :_thread_id(std::this_thread::get_id())
        {
            _eventfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);//创建eventfd
            if(_eventfd < 0){
                LOG_ERR("create eventfd failed %s",strerror(errno));
                exit(1);
            }
            _eventfd_channel = std::make_unique<Channel>(this,_eventfd);
            _eventfd_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd,this));
            _eventfd_channel->EnableReading();//启动eventfd的读事件监控
        }
        bool IsInLoop()//判断是否是当前线程是否是EventLoop对应的线程
        {
            //std::this_thread::get_id()获取当前线程id
            //_thread_id是EventLoop对应的线程id
            return std::this_thread::get_id() == _thread_id;
        }
        
        void AddTaskInLoop(const Func_t &cb)//将操作放入任务队列（放到eventloop的任务队列中）
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _tasks.push_back(cb);
            }
            //唤醒有可能因为没用事件就绪而导致的epoll阻塞（本质就是给eventfd写入数据，eventfd就会触发epoll的读事件）
            WriteEventfd();
        }
        void RuninLoop(const Func_t &cb)//先判断任务是否在当前线程中，如果不是，则将任务放入任务队列，是则直接执行
        {
            if(IsInLoop()){
                cb();
            }else{
                AddTaskInLoop(cb);
            }
        }
        
        void AddEvent(Channel* channel)
        {
            _epoll.AddChannel(channel);
            _epoll.ModifChannel(channel);
        }
        void RemoveEvent(Channel* channel)
        {
            _epoll.DelChannel(channel);
            _epoll.ModifChannel(channel);
        }
        void ModifyEvent(Channel* channel)
        {
            _epoll.ModifChannel(channel);
        }
        void Start()//启动EventLoop
        {
            //1.事件监控
            std::vector<Channel *> active;//用于获取就绪事件的channel
            _epoll.WaitEventsFromChannels(&active);
            //2.就绪事件处理
            for(auto &channel: active){
                channel->HandleEvent();
            }
            //3.执行任务
            RunAllTasks();
        }
};

